<!DOCTYPE html>
<!--suppress JSSuspiciousNameCombination -->
<html>

<head>
    <meta charset="utf-8"/>
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <meta name="keywords" content=""/>
    <meta name="description" content=""/>
    <meta name="apple-mobile-web-app-capable" content="no"/>
    <meta name="format-detection" content="telephone=no">
    <title>简单模板</title>
    <link rel="stylesheet" type="text/css" href="./css/style-index.css?v=1.00"/>

    <!--引用requirejs 及 config 文件-->
    <script src="https://lib.baomitu.com/vue/2.5.16/vue.min.js"></script>
    <script src="https://lib.baomitu.com/element-ui/2.3.6/index.js"></script>
    <link rel="stylesheet" href="https://lib.baomitu.com/element-ui/2.3.6/theme-chalk/index.css">
    <script src="https://lib.baomitu.com/require.js/2.3.5/require.min.js"></script>
    <script src="./js/lib/webLib/requireconfig.js?v=1.00"></script>
    <script>
        requirejs({
            baseUrl: "js",
            urlArgs: "v=1.00",
        })
    </script>
    <style>
        [v-cloak] {
            visibility: hidden;
        }
    </style>
</head>

<body class="page dome-page">


<canvas class="test">

</canvas>

<canvas class="test2" style="display: none">

</canvas>

<div id="app" v-cloak>

    <h3>画布大小</h3>
    <el-row style="width: 600px">
        <el-col :span="8">
            <el-input-number v-model="width" :min="1" :max="1900" label="长度" :step="5"></el-input-number>
        </el-col>
        <el-col :span="8">
            <el-input-number v-model="height" :min="1" :max="1900" label="宽度" :step="5"></el-input-number>
        </el-col>
        <el-col :span="8" style="line-height: 30px;text-align: center">
            最优解:{{num}}
        </el-col>
    </el-row>

    <h3>矩形大小</h3>
    <el-row style="width: 600px">
        <el-col :span="8">
            <el-input-number v-model="rectW" :min="1" :max="1900" label="宽度" :step="2"></el-input-number>
        </el-col>
        <el-col :span="8">
            <el-input-number v-model="rectH" :min="1" :max="1900" label="高度" :step="2"></el-input-number>
        </el-col>
    </el-row>

</div>

<script>
    require(['Ani', 'lodash', 'store'], function (Ani, _, Store) {

        class base {
            constructor() {
                this.RectArr = [];
            }

            //通过短边计算最优排列
            countMaxBySmallRest(Cw, Ch, Rw, Rh, Rp) {
                let Rbig = Rw > Rh ? Rw + Rp : Rh + Rp;
                let Rless = Rw > Rh ? Rh + Rp : Rw + Rp;
                let Rgap = Rbig - Rless;
                let RlessNum = parseInt(Cw / Rless);
                let CwRestNum = Cw - RlessNum * Rless;
                let ResultArr = [];
                if (CwRestNum <= Rgap) {
                    ResultArr.length = RlessNum;
                    ResultArr.fill([Rless - Rp, Rbig - Rp]);
                } else {
                    let gapNum = parseInt(CwRestNum / Rgap);
                    if (gapNum > RlessNum) {
                        gapNum = 0;
                    }
                    ResultArr.length = Math.abs(RlessNum - gapNum);
                    ResultArr.fill([Rless - Rp, Rbig - Rp]);
                    for (let i = 0; i < gapNum; i++) {
                        ResultArr.push([Rbig - Rp, Rless - Rp])
                    }
                }
                return ResultArr
            }

            //通过长边计算最优排列
            countMaxByBigRest(Cw, Ch, Rw, Rh, Rp) {
                let Rbig = Rw > Rh ? Rw + Rp : Rh + Rp;
                let Rless = Rw > Rh ? Rh + Rp : Rw + Rp;
                let RbigNum = Math.ceil(Cw / Rbig);
                let ResultArr = [];
                let RestArr = [], RestCountArr = [];
                let BrectArr = [], SrectArr = [];
                //最小值位置
                let minNumPos;
                //穷举所有可能
                for (let i = RbigNum - 1; i >= 0; i--) {
                    let restNum = ((Cw - i * Rbig) / Rless).toString().split(".");
                    RestCountArr.push(parseInt(restNum[0]));
                    RestArr.push(restNum.length === 2 ? parseInt(restNum[1]) : 0)
                }
                //获得排序的最小结果 并且定位
                minNumPos = RestArr.indexOf(_.clone(RestArr).sort()[0]);
                BrectArr.length = RbigNum - minNumPos - 1;
                SrectArr.length = RestCountArr[minNumPos];
                ResultArr = [...(BrectArr.fill([Rbig - Rp, Rless - Rp])), ...(SrectArr.fill([Rless - Rp, Rbig - Rp]))];

                let FistRect = {
                    w: this.RectArr[0][0][2],
                    h: this.RectArr[0][0][3]
                };

                ResultArr.sort(function (old, last) {
                    return FistRect.w < last[1]
                });

                return ResultArr
            }

            //通过参数画出矩形
            drawRect(Pos, RectArr, Type, Cw, Ch, Rw, Rh, Rp) {
                let DrawArr = [];
                if (Type === "col") {
                    _.each(RectArr, (item, index) => {
                        //长宽互调
                        item = item.reverse();
                    })
                }

                RectArr.forEach((item, index) => {
                    let AxisY, AxisX;
                    if (Type === "row") {
                        AxisX = index === 0 ? Pos.x + Rp : DrawArr[index - 1][0] + RectArr[index - 1][0] + Rp;
                        DrawArr.push([AxisX, Pos.y, ...RectArr[index]]);
                    } else if (Type === "col") {
                        AxisY = index === 0 ? Pos.y + Rp : DrawArr[index - 1][1] + RectArr[index - 1][1] + Rp;
                        DrawArr.push([Pos.x, AxisY, ...RectArr[index]]);
                    }
                });
                return DrawArr
            }

            //根据对比确定位置
            getPosByDisaffinity(RectArr) {
                let x = 0, y = 0;
                let FirstRect = {
                    w: RectArr[0][0][2],
                    h: RectArr[0][0][3]
                };
                //确定第一排
                if (RectArr.length > 0) {
                    _.each(RectArr, (item, index) => {
                        if (item[0][2] !== FirstRect.w) {
                            y = index - 1;
                            return false
                        }
                        if (index === RectArr.length - 1) {
                            y = RectArr.length - 1
                        }
                    });

                    _.each(RectArr[0], (item, index) => {
                        if (item[2] !== FirstRect.w) {
                            x = index - 1;
                            return false
                        }
                        if (index === RectArr[0].length - 1) {
                            x = RectArr[0].length - 1
                        }
                    });
                }
                return {
                    x, y
                };
            }

            //获得数据
            getData() {
                return this.RectArr
            }
        }

        class PermutationCol extends base {
            constructor(canvasW, canvasH, rectH, rectW, paddingWidth, type = 1) {
                super();
                this.options = {
                    canvasW, canvasH, rectH, rectW, paddingWidth, type
                };
                this.getFirstRow();
                this.getTwoRow();
                this.getThreeRow();
                this.getFourRow();
                this.getFiveRow();
                this.getSixRow();
            }

            getFirstRow() {
                let {canvasW, canvasH, rectH, rectW, paddingWidth, type} = this.options;
                let ColrSortResult = this.countMaxBySmallRest(canvasH, canvasW, rectW, rectH, paddingWidth);

                let FirstRow = [];
                for (let i = 0; i <= ColrSortResult.length - 1; i++) {
                    let AxisY = i > 0 ? (ColrSortResult[i - 1][0] + paddingWidth) + FirstRow[i - 1][1] : paddingWidth;
                    FirstRow.push([paddingWidth, AxisY, ColrSortResult[i][1], ColrSortResult[i][0]])
                }
                //转换为纵向数组
                FirstRow.forEach((Row, index) => {
                    this.RectArr[index] = [];
                    this.RectArr[index].push(FirstRow[index])
                });
            }

            getTwoRow() {
                let {canvasW, canvasH, rectH, rectW, paddingWidth} = this.options;
                let FirstRect = {
                    h: this.RectArr[0][0][2],
                    w: this.RectArr[0][0][3]
                };
                let rowSortResult = this.countMaxByBigRest(canvasW - FirstRect.h, canvasH, rectW, rectH, paddingWidth);
                this.RectArr[0].push(...this.drawRect({
                    x: FirstRect.h + paddingWidth,
                    y: paddingWidth
                }, rowSortResult, 'row', canvasW, canvasH, rectW, rectH, paddingWidth))


                //   console.log(this.RectArr[0])
            }

            //补中间
            getThreeRow() {
                let {canvasW, canvasH, rectH, rectW, paddingWidth} = this.options;
                let {x, y} = this.getPosByDisaffinity(this.RectArr);
                if (x > 0 && y > 0) {
                    let FirstRect = {
                        h: this.RectArr[0][0][2],
                        w: this.RectArr[0][0][3]
                    };
                    let pos = {
                        x: this.RectArr[0][1][0] - paddingWidth,
                        y: this.RectArr[1][0][1]
                    };
                    let rectRowArr = [];
                    rectRowArr.length = x;
                    for (let i = 0; i < y; i++) {
                        pos.y = i === 0
                            ? this.RectArr[1][0][1]
                            : ((i + 1) * (FirstRect.w + paddingWidth)) + paddingWidth;
                        rectRowArr.fill([FirstRect.h, FirstRect.w]);
                        this.RectArr[i + 1].push(...this.drawRect(pos, rectRowArr, "row", canvasW, canvasH, rectW, rectH, paddingWidth));
                    }
                }
            }

            //补下边
            getFourRow() {
                let {canvasW, canvasH, rectH, rectW, paddingWidth} = this.options;
                let needFillRectArr = [];
                //底边最长宽度
                let RectArrBottomWidth = 0;
                let FirstRect = {
                    h: this.RectArr[0][0][2],
                    w: this.RectArr[0][0][3]
                };
                let {x, y} = this.getPosByDisaffinity(this.RectArr);
                //图形下边是否有相反方向的
                let RectArrNoSameYLength = this.RectArr.length - y - 1;
                let RectArrNoSameXLength = this.RectArr[0].length - x - 1;
                //如果有则补全
                if (RectArrNoSameYLength > 0) {
                    let drawRectArr;
                    //获得底部剩余长度
                    RectArrBottomWidth = (FirstRect.h + paddingWidth) * (x + 1) - (FirstRect.w + paddingWidth);
                    //以相同模式进行填装操作
                    needFillRectArr.length = parseInt(RectArrBottomWidth / (FirstRect.w + paddingWidth));
                    needFillRectArr.fill([FirstRect.w, FirstRect.h]);

                    //填充起始位置
                    let pos = {
                        x: paddingWidth + FirstRect.w,
                        y: (FirstRect.w + paddingWidth) * (y + 1) + paddingWidth
                    };
                    for (let i = 0; i < RectArrNoSameYLength; i++) {
                        let countY = i === 0 ? pos.y : pos.y + i * (FirstRect.h + paddingWidth);
                        drawRectArr = this.drawRect({
                            x: pos.x,
                            y: countY
                        }, needFillRectArr, "row", RectArrBottomWidth, canvasH, rectW, rectH, paddingWidth);
                        this.RectArr[y + 1 + i] = [...this.RectArr[y + 1 + i], ...drawRectArr];
                    }
                    // console.log(RectArrNoSameYLength, RectArrNoSameXLength, RectArrBottomWidth, drawRectArr,this.RectArr[y + 1])
                }
            }

            //
            getFiveRow() {
                let {canvasW, canvasH, rectH, rectW, paddingWidth} = this.options;
                let {x, y} = this.getPosByDisaffinity(this.RectArr);
                let RestRectX = this.RectArr[0].length - x - 1;
                let DrawRectArr = [];

                //所剩面积的高
                if (x > 0) {
                    let RestAreaH = canvasH - this.RectArr[0][0][2];
                    let RestAreaW = canvasW - ((x + 1) * (rectW + paddingWidth));
                    let RestArr = this.countMaxByBigRest(RestAreaH, canvasH, rectW, rectH, paddingWidth);
                    RestArr.forEach((item, index) => {
                        let RowArr = [];
                        RowArr.length = RestRectX;
                        RowArr.fill(item);
                        DrawRectArr.push(RowArr)
                    });
                }
            }

            //
            getSixRow() {
                let {canvasW, canvasH, rectH, rectW, paddingWidth} = this.options;
                //确定矩形面积
                let {x, y} = this.getPosByDisaffinity(this.RectArr);
                let FirstRect = {
                    h: this.RectArr[0][0][2],
                    w: this.RectArr[0][0][3]
                };
                //获得剩余的长宽高和面积
                let DiffColH = this.RectArr[0][x][2];
                let RestH = canvasH - DiffColH;
                let RestW = canvasW - ((DiffColH + paddingWidth) * (x + 1));
                let rowSortResult = this.countMaxBySmallRest(RestH, canvasH, rectW, rectH, paddingWidth);
                let DrawRectArr = this.drawRect({
                    x: (x + 1) * (FirstRect.h + paddingWidth) + paddingWidth,
                    y: FirstRect.h + paddingWidth
                }, rowSortResult, 'col', canvasW, canvasH, rectW, rectH, paddingWidth);

                _.each(DrawRectArr, (item, index) => {
                    this.RectArr[index + 1].push(item)
                });
            }
        }

        class PermutationRow extends base {
            constructor(canvasW, canvasH, rectH, rectW, paddingWidth, type = 1) {
                super();
                this.FirstRowFilterPos = -1;
                this.options = {
                    canvasW, canvasH, rectH, rectW, paddingWidth, type
                };
                this.getFirstRow();
                // this.getTwoRow();
            }

            getFirstRow() {
                let {canvasW, canvasH, rectH, rectW, paddingWidth, type} = this.options;
                let rowSortResult = this.countMaxBySmallRest(canvasW, canvasH, rectW, rectH, paddingWidth);
                let FirstRow = [];
                for (let i = 0; i <= rowSortResult.length - 1; i++) {
                    let AxisX = i > 0 ? (rowSortResult[i - 1][0] + paddingWidth) + FirstRow[i - 1][0] : paddingWidth;
                    FirstRow.push([AxisX, paddingWidth, ...rowSortResult[i]])
                }
                this.RectArr.push(FirstRow);
            }

            getTwoRow() {
                let {canvasW, canvasH, rectH, rectW, paddingWidth} = this.options;
                let FirstRect = {
                    h: this.RectArr[0][0][2],
                    w: this.RectArr[0][0][3]
                }
                // console.log(FirstRect.h,this.countMaxBySmallRest(canvasH - FirstRect.h,rectW,rectH,paddingWidth))
            }

            getData() {
                return this.RectArr
            }
        }

        new Vue({
            el: "#app",
            data: function () {
                if (!Store.get("options")) {
                    return {
                        width: 800,
                        height: 66,
                        rectW: 170,
                        rectH: 100,
                        padding: 5
                    }
                } else {
                    let {options} = Store.get("options");
                    return {
                        width: options.width,
                        height: options.height,
                        rectW: options.rectW,
                        rectH: options.rectH,
                        padding: options.padding
                    }
                }
            },
            methods: {
                change() {
                    this.initCanvas();
                    Store.set('options', {
                        options: {
                            width: this.width,
                            height: this.height,
                            rectW: this.rectW,
                            rectH: this.rectH,
                            padding: this.padding
                        }
                    })
                },
                initCanvas() {
                    let cW, cH;
                    let testCol, testRow;
                    if (this.width > this.height) {
                        cW = this.width;
                        cH = this.height;
                    } else {
                        cW = this.height;
                        cH = this.width;
                    }
                    testCol = new Ani.Game(cW, cH, '.test', {
                        create: () => {
                            let permutationRect = new PermutationCol(cW, cH, this.rectH, this.rectW, this.padding);
                            permutationRect.getData().forEach(rows => {
                                rows.forEach(col => {
                                    testCol.add.rect(col);
                                })
                            })
                        }
                    });

                    testRow = new Ani.Game(cW, cH, '.test2', {
                        create: () => {
                            let permutationRect = new PermutationRow(cW, cH, this.rectH, this.rectW, this.padding);
                            permutationRect.getData().forEach(rows => {
                                rows.forEach(col => {
                                    testRow.add.rect(col);
                                })
                            })
                        }
                    });
                }
            },
            mounted() {
                console.time("time");
                this.initCanvas();
                console.timeEnd('time')
            },
            watch: {
                width: "change",
                height: "change",
                rectW: "change",
                rectH: "change"
            },
            computed: {
                num: function () {
                    return parseInt(((this.width * this.height))
                        / ((this.rectW + this.padding) * (this.rectH + this.padding)))
                }
            }
        })

    })
</script>
</body>

</html>
